<html dir="ltr" lang="zh">

<head>
  <meta charset="utf-8">
  <meta name="google" value="notranslate">

  <script>
    function addRow(name, url, isdir,
      size, size_string, date_modified, date_modified_string) {
      if (name == "." || name == "..")
        return;

      var root = document.location.pathname;
      if (root.substr(-1) !== "/")
        root += "/";

      var tbody = document.getElementById("tbody");
      var row = document.createElement("tr");
      var file_cell = document.createElement("td");
      var link = document.createElement("a");

      link.className = isdir ? "icon dir" : "icon file";

      if (isdir) {
        name = name + "/";
        url = url + "/";
        size = 0;
        size_string = "";
      } else {
        link.draggable = "true";
        link.addEventListener("dragstart", onDragStart, false);
      }
      link.innerText = name;
      link.href = root + url;

      file_cell.dataset.value = name;
      file_cell.appendChild(link);

      row.appendChild(file_cell);
      row.appendChild(createCell(size, size_string));
      row.appendChild(createCell(date_modified, date_modified_string));

      tbody.appendChild(row);
    }

    function onDragStart(e) {
      var el = e.srcElement;
      var name = el.innerText.replace(":", "");
      var download_url_data = "application/octet-stream:" + name + ":" + el.href;
      e.dataTransfer.setData("DownloadURL", download_url_data);
      e.dataTransfer.effectAllowed = "copy";
    }

    function createCell(value, text) {
      var cell = document.createElement("td");
      cell.setAttribute("class", "detailsColumn");
      cell.dataset.value = value;
      cell.innerText = text;
      return cell;
    }

    function start(location) {
      var header = document.getElementById("header");
      header.innerText = header.innerText.replace("LOCATION", location);

      document.getElementById("title").innerText = header.innerText;
    }

    function onHasParentDirectory() {
      var box = document.getElementById("parentDirLinkBox");
      box.style.display = "block";

      var root = document.location.pathname;
      if (!root.endsWith("/"))
        root += "/";

      var link = document.getElementById("parentDirLink");
      link.href = root + "..";
    }

    function onListingParsingError() {
      var box = document.getElementById("listingParsingErrorBox");
      box.innerHTML = box.innerHTML.replace("LOCATION", encodeURI(document.location)
        + "?raw");
      box.style.display = "block";
    }

    function sortTable(column) {
      var theader = document.getElementById("theader");
      var oldOrder = theader.cells[column].dataset.order || '1';
      oldOrder = parseInt(oldOrder, 10)
      var newOrder = 0 - oldOrder;
      theader.cells[column].dataset.order = newOrder;

      var tbody = document.getElementById("tbody");
      var rows = tbody.rows;
      var list = [], i;
      for (i = 0; i < rows.length; i++) {
        list.push(rows[i]);
      }

      list.sort(function (row1, row2) {
        var a = row1.cells[column].dataset.value;
        var b = row2.cells[column].dataset.value;
        if (column) {
          a = parseInt(a, 10);
          b = parseInt(b, 10);
          return a > b ? newOrder : a < b ? oldOrder : 0;
        }

        // Column 0 is text.
        if (a > b)
          return newOrder;
        if (a < b)
          return oldOrder;
        return 0;
      });

      // Appending an existing child again just moves it.
      for (i = 0; i < list.length; i++) {
        tbody.appendChild(list[i]);
      }
    }

    // Add event handlers to column headers.
    function addHandlers(element, column) {
      element.onclick = (e) => sortTable(column);
      element.onkeydown = (e) => {
        if (e.key == 'Enter' || e.key == ' ') {
          sortTable(column);
          e.preventDefault();
        }
      };
    }

    function onLoad() {
      addHandlers(document.getElementById('nameColumnHeader'), 0);
      addHandlers(document.getElementById('sizeColumnHeader'), 1);
      addHandlers(document.getElementById('dateColumnHeader'), 2);
    }

    window.addEventListener('DOMContentLoaded', onLoad);
  </script>

  <style>
    h1 {
      border-bottom: 1px solid #c0c0c0;
      margin-bottom: 10px;
      padding-bottom: 10px;
      white-space: nowrap;
    }

    table {
      border-collapse: collapse;
    }

    th {
      cursor: pointer;
    }

    td.detailsColumn {
      -webkit-padding-start: 2em;
      text-align: end;
      white-space: nowrap;
    }

    a.icon {
      -webkit-padding-start: 1.5em;
      text-decoration: none;
      user-select: auto;
    }

    a.icon:hover {
      text-decoration: underline;
    }

    a.file {
      background: url(" ") left top no-repeat;
    }

    a.dir {
      background: url(" ") left top no-repeat;
    }

    a.up {
      background: url(" ") left top no-repeat;
    }

    html[dir=rtl] a {
      background-position-x: right;
    }

    #parentDirLinkBox {
      margin-bottom: 10px;
      padding-bottom: 10px;
    }

    #listingParsingErrorBox {
      border: 1px solid black;
      background: #fae691;
      padding: 10px;
      display: none;
    }
  </style>

  <title id="title">{{ title }}</title>

</head>

<body>

  <div id="listingParsingErrorBox">糟糕！Google Chrome无法解读服务器所发送的数据。请<a
      href="http://code.google.com/p/chromium/issues/entry">报告错误</a>，并附上<a href="LOCATION">原始列表</a>。</div>

  <h1 id="header">/Users/china/Documents/lujianying/nodejs/www/ 的索引</h1>

  <div id="parentDirLinkBox" style="display: block;">
    <a id="parentDirLink" class="icon up" href="/Users/china/Documents/lujianying/nodejs/02/code/template.html/..">
      <span id="parentDirText">[上级目录]</span>
    </a>
  </div>

  <table>
    <thead>
      <tr class="header" id="theader">
        <th id="nameColumnHeader" tabindex="0" role="button" data-order="1">名称</th>
        <th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button" data-order="-1">
          大小
        </th>
        <th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button" data-order="-1">
          修改日期
        </th>
      </tr>
    </thead>
    <tbody id="tbody">
      {{ each files }}
      <tr>
        <td data-value=".DS_Store"><a class="icon file" draggable="true"
            href="/Users/china/Documents/lujianying/nodejs/02/code/template.html/.DS_Store">{{ $value }}</a></td>
        <td class="detailsColumn" data-value="6148">6.0 kB</td>
        <td class="detailsColumn" data-value="1634389888">2021/10/16 下午9:11:28</td>
      </tr>
      {{ /each }}
    </tbody>
  </table>




  <!-- <script>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.

    /**
     * @fileoverview This file defines a singleton which provides access to all data
     * that is available as soon as the page's resources are loaded (before DOM
     * content has finished loading). This data includes both localized strings and
     * any data that is important to have ready from a very early stage (e.g. things
     * that must be displayed right away).
     *
     * Note that loadTimeData is not guaranteed to be consistent between page
     * refreshes (https://crbug.com/740629) and should not contain values that might
     * change if the page is re-opened later.
     */

    /** @type {!LoadTimeData} */
    // eslint-disable-next-line no-var
    var loadTimeData;

    class LoadTimeData {
      constructor() {
        /** @type {?Object} */
        this.data_ = null;
      }

      /**
       * Sets the backing object.
       *
       * Note that there is no getter for |data_| to discourage abuse of the form:
       *
       *     var value = loadTimeData.data()['key'];
       *
       * @param {Object} value The de-serialized page data.
       */
      set data(value) {
        expect(!this.data_, 'Re-setting data.');
        this.data_ = value;
      }

      /**
       * @param {string} id An ID of a value that might exist.
       * @return {boolean} True if |id| is a key in the dictionary.
       */
      valueExists(id) {
        return id in this.data_;
      }

      /**
       * Fetches a value, expecting that it exists.
       * @param {string} id The key that identifies the desired value.
       * @return {*} The corresponding value.
       */
      getValue(id) {
        expect(this.data_, 'No data. Did you remember to include strings.js?');
        const value = this.data_[id];
        expect(typeof value !== 'undefined', 'Could not find value for ' + id);
        return value;
      }

      /**
       * As above, but also makes sure that the value is a string.
       * @param {string} id The key that identifies the desired string.
       * @return {string} The corresponding string value.
       */
      getString(id) {
        const value = this.getValue(id);
        expectIsType(id, value, 'string');
        return /** @type {string} */ (value);
      }

      /**
       * Returns a formatted localized string where $1 to $9 are replaced by the
       * second to the tenth argument.
       * @param {string} id The ID of the string we want.
       * @param {...(string|number)} var_args The extra values to include in the
       *     formatted output.
       * @return {string} The formatted string.
       */
      getStringF(id, var_args) {
        const value = this.getString(id);
        if (!value) {
          return '';
        }

        const args = Array.prototype.slice.call(arguments);
        args[0] = value;
        return this.substituteString.apply(this, args);
      }

      /**
       * Returns a formatted localized string where $1 to $9 are replaced by the
       * second to the tenth argument. Any standalone $ signs must be escaped as
       * $$.
       * @param {string} label The label to substitute through.
       *     This is not an resource ID.
       * @param {...(string|number)} var_args The extra values to include in the
       *     formatted output.
       * @return {string} The formatted string.
       */
      substituteString(label, var_args) {
        const varArgs = arguments;
        return label.replace(/\$(.|$|\n)/g, function (m) {
          expect(m.match(/\$[$1-9]/), 'Unescaped $ found in localized string.');
          return m === '$$' ? '$' : varArgs[m[1]];
        });
      }

      /**
       * Returns a formatted string where $1 to $9 are replaced by the second to
       * tenth argument, split apart into a list of pieces describing how the
       * substitution was performed. Any standalone $ signs must be escaped as $$.
       * @param {string} label A localized string to substitute through.
       *     This is not an resource ID.
       * @param {...(string|number)} var_args The extra values to include in the
       *     formatted output.
       * @return {!Array<!{value: string, arg: (null|string)}>} The formatted
       *     string pieces.
       */
      getSubstitutedStringPieces(label, var_args) {
        const varArgs = arguments;
        // Split the string by separately matching all occurrences of $1-9 and of
        // non $1-9 pieces.
        const pieces = (label.match(/(\$[1-9])|(([^$]|\$([^1-9]|$))+)/g) ||
          []).map(function (p) {
            // Pieces that are not $1-9 should be returned after replacing $$
            // with $.
            if (!p.match(/^\$[1-9]$/)) {
              expect(
                (p.match(/\$/g) || []).length % 2 === 0,
                'Unescaped $ found in localized string.');
              return { value: p.replace(/\$\$/g, '$'), arg: null };
            }

            // Otherwise, return the substitution value.
            return { value: varArgs[p[1]], arg: p };
          });

        return pieces;
      }

      /**
       * As above, but also makes sure that the value is a boolean.
       * @param {string} id The key that identifies the desired boolean.
       * @return {boolean} The corresponding boolean value.
       */
      getBoolean(id) {
        const value = this.getValue(id);
        expectIsType(id, value, 'boolean');
        return /** @type {boolean} */ (value);
      }

      /**
       * As above, but also makes sure that the value is an integer.
       * @param {string} id The key that identifies the desired number.
       * @return {number} The corresponding number value.
       */
      getInteger(id) {
        const value = this.getValue(id);
        expectIsType(id, value, 'number');
        expect(value === Math.floor(value), 'Number isn\'t integer: ' + value);
        return /** @type {number} */ (value);
      }

      /**
       * Override values in loadTimeData with the values found in |replacements|.
       * @param {Object} replacements The dictionary object of keys to replace.
       */
      overrideValues(replacements) {
        expect(
          typeof replacements === 'object',
          'Replacements must be a dictionary object.');
        for (const key in replacements) {
          this.data_[key] = replacements[key];
        }
      }

      /**
       * Reset loadTimeData's data. Should only be used in tests.
       * @param {?Object} newData The data to restore to, when null restores to
       *    unset state.
       */
      resetForTesting(newData = null) {
        this.data_ = newData;
      }

      /**
       * @return {boolean} Whether loadTimeData.data has been set.
       */
      isInitialized() {
        return this.data_ !== null;
      }
    }

    /**
     * Checks condition, throws error message if expectation fails.
     * @param {*} condition The condition to check for truthiness.
     * @param {string} message The message to display if the check fails.
     */
    function expect(condition, message) {
      if (!condition) {
        throw new Error(
          'Unexpected condition on ' + document.location.href + ': ' + message);
      }
    }

    /**
     * Checks that the given value has the given type.
     * @param {string} id The id of the value (only used for error message).
     * @param {*} value The value to check the type on.
     * @param {string} type The type we expect |value| to be.
     */
    function expectIsType(id, value, type) {
      expect(
        typeof value === type, '[' + value + '] (' + id + ') is not a ' + type);
    }

    expect(!loadTimeData, 'should only include this file once');
    loadTimeData = new LoadTimeData;

    // Expose |loadTimeData| directly on |window|, since within a JS module the
    // scope is local and not all files have been updated to import the exported
    // |loadTimeData| explicitly.
    window.loadTimeData = loadTimeData;

    console.warn('crbug/1173575, non-JS module files deprecated.');</script>
  <script>loadTimeData.data = { "header": "LOCATION 的索引", "headerDateModified": "修改日期", "headerName": "名称", "headerSize": "大小", "language": "zh", "listingParsingErrorBoxText": "糟糕！Google Chrome无法解读服务器所发送的数据。请\u003Ca href=\"http://code.google.com/p/chromium/issues/entry\">报告错误\u003C/a>，并附上\u003Ca href=\"LOCATION\">原始列表\u003C/a>。", "parentDirText": "[上级目录]", "textdirection": "ltr" };</script>
  <script>start("/Users/china/Documents/lujianying/nodejs/www/");</script>
  <script>onHasParentDirectory();</script>
  <script>addRow("apple", "apple", 1, 96, "96 B", 1634219681, "2021/10/14 下午9:54:41");</script>
  <script>addRow("img", "img", 1, 96, "96 B", 1634221923, "2021/10/14 下午10:32:03");</script>
  <script>addRow(".DS_Store", ".DS_Store", 0, 6148, "6.0 kB", 1634389888, "2021/10/16 下午9:11:28");</script>
  <script>addRow("a.txt", "a.txt", 0, 16, "16 B", 1634220425, "2021/10/14 下午10:07:05");</script>
  <script>addRow("index.html", "index.html", 0, 277, "277 B", 1634219681, "2021/10/14 下午9:54:41");</script> -->
</body>

</html>